using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace RichFrame.Event
{
    /// <summary>
    /// 事件管理器
    /// </summary>
    public class EventManager : MonoBehaviour
    {
        /// <summary>
        /// 全局事件管理器，永远存在
        /// </summary>
        public static EventManager Global
        { 
            get
            {
                if(_Global == null)
                {
                    _Global = new GameObject("[Global Event Manager]").AddComponent<EventManager>();
                    DontDestroyOnLoad(_Global.gameObject);
                }
                return _Global;
            }
        }
        static EventManager _Global;

        /// <summary>
        /// 场景事件管理器，当场景被卸载时销毁
        /// </summary>
        public static EventManager Current
        {
            get
            {
                int sceneHash = SceneManager.GetActiveScene().GetHashCode();
                if(_Current == null)
                {
                    _Current = CreateEventManager();
                }
                return _Current;
            }
        }
        static EventManager _Current;

        static EventManager CreateEventManager()
        {
            Scene activeScene = SceneManager.GetActiveScene();
            int sceneHash = activeScene.GetHashCode();
            EventManager eventManager = new GameObject($"[Current Event Manager-{sceneHash}]").AddComponent<EventManager>();

            return eventManager;
        }

        static EventManager()
        {
            SceneManager.sceneUnloaded += OnSceneUnloaded;
        }

        static void OnSceneUnloaded(Scene scene)
        {
            if(_Current != null && _Current.SceneHash == scene.GetHashCode())
            {
                _Current.CleanAllEvents();
            }
        }

        public int SceneHash
        {
            get
            {
                return _SceneHash;
            }
        }
        int _SceneHash;
        public Dictionary<string, List<Delegate>> eventsDic = new Dictionary<string, List<Delegate>>();


        /// <summary>
        /// 监听一个事件
        /// </summary>
        /// <param name="eventName">事件名称</param>
        /// <param name="listener">监听方法</param>
        void ListenEvent(string eventName, Delegate listener)
        {
            List<Delegate> listeners;
            if (eventsDic.TryGetValue(eventName, out listeners))
            {
                if (!listeners.Contains(listener))
                {
                    listeners.Add(listener);
                }
            }
            else
            {
                listeners = new List<Delegate>();
                listeners.Add(listener);
                eventsDic.Add(eventName, listeners);
            }
        }
        /// <summary>
        /// 移除一个监听
        /// </summary>
        /// <param name="eventName">事件名</param>
        /// <param name="id">id</param>
        void RemoveEvent(string eventName, Delegate handler)
        {
            List<Delegate> listeners;
            if (eventsDic.TryGetValue(eventName, out listeners))
            {
                listeners.Remove(handler);
                if (listeners.Count == 0)
                    eventsDic.Remove(eventName);
            }
        }
        /// <summary>
        /// 清除所有事件
        /// </summary>
        void CleanAllEvents()
        {
            eventsDic.Clear();
        }

        #region 监听事件
        public void ListenEvent(string eventName,Action handler)
        {
            ListenEvent(eventName, (Delegate)handler);
        }
        public void ListenEvent<T>(string eventName,Action<T> handler)
        {
            ListenEvent(eventName, (Delegate)handler);
        }
        public void ListenEvent<T,T1>(string eventName, Action<T, T1> handler)
        {
            ListenEvent(eventName, (Delegate)handler);
        }
        public void ListenEvent<T, T1,T2>(string eventName, Action<T, T1,T2> handler)
        {
            ListenEvent(eventName, (Delegate)handler);
        }
        public void ListenEvent<T, T1, T2,T3>(string eventName, Action<T, T1, T2,T3> handler)
        {
            ListenEvent(eventName, (Delegate)handler);
        }
        public void ListenEvent<T, T1, T2, T3,T4>(string eventName, Action<T, T1, T2, T3,T4> handler)
        {
            ListenEvent(eventName, (Delegate)handler);
        }
        public void ListenEvent<T, T1, T2, T3, T4,T5>(string eventName, Action<T, T1, T2, T3, T4,T5> handler)
        {
            ListenEvent(eventName, (Delegate)handler);
        }
        #endregion

        #region 移除事件监听
        public void RemoveListener(string eventName,Action handler)
        {
            RemoveEvent(eventName, handler);
        }
        public void RemoveListener<T>(string eventName, Action<T> handler)
        {
            RemoveEvent(eventName, handler);
        }
        public void RemoveListener<T, T1>(string eventName, Action<T, T1> handler)
        {
            RemoveEvent(eventName, handler);
        }
        public void RemoveListener<T, T1, T2>(string eventName, Action<T, T1, T2> handler)
        {
            RemoveEvent(eventName, handler);
        }
        public void RemoveListener<T, T1, T2, T3>(string eventName, Action<T, T1, T2, T3> handler)
        {
            RemoveEvent(eventName, handler);
        }
        public void RemoveListener<T, T1, T2, T3, T4>(string eventName, Action<T, T1, T2, T3, T4> handler)
        {
            RemoveEvent(eventName, handler);
        }
        public void RemoveListener<T, T1, T2, T3, T4, T5>(string eventName, Action<T, T1, T2, T3, T4, T5> handler)
        {
            RemoveEvent(eventName,handler);
        }
        #endregion

        #region 执行事件
        public void ExecuteEvent(string eventName)
        {
            List<Delegate> listeners;
            if (eventsDic.TryGetValue(eventName, out listeners))
            {
                foreach (var item in listeners)
                {
                    ((Action)item)();
                }
            }
        }
        public void ExecuteEvent<T>(string eventName,T arg0)
        {
            List<Delegate> listeners;
            if (eventsDic.TryGetValue(eventName, out listeners))
            {
                foreach (var item in listeners)
                {
                    ((Action<T>)item)(arg0);
                }
            }
        }
        public void ExecuteEvent<T, T1>(string eventName, T arg0, T1 arg1)
        {
            List<Delegate> listeners;
            if (eventsDic.TryGetValue(eventName, out listeners))
            {
                foreach (var item in listeners)
                {
                    ((Action<T,T1>)item)(arg0,arg1);
                }
            }
        }
        public void ExecuteEvent<T, T1, T2>(string eventName, T arg0, T1 arg1, T2 arg2)
        {
            List<Delegate> listeners;
            if (eventsDic.TryGetValue(eventName, out listeners))
            {
                foreach (var item in listeners)
                {
                    ((Action<T, T1, T2>)item)(arg0, arg1, arg2);
                }
            }
        }
        public void ExecuteEvent<T, T1, T2, T3>(string eventName, T arg0, T1 arg1, T2 arg2, T3 arg3)
        {
            List<Delegate> listeners;
            if (eventsDic.TryGetValue(eventName, out listeners))
            {
                foreach (var item in listeners)
                {
                    ((Action<T, T1, T2, T3>)item)(arg0, arg1, arg2, arg3);
                }
            }
        }
        public void ExecuteEvent<T, T1, T2, T3, T4>(string eventName, T arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
        {
            List<Delegate> listeners;
            if (eventsDic.TryGetValue(eventName, out listeners))
            {
                foreach (var item in listeners)
                {
                    ((Action<T, T1, T2, T3, T4>)item)(arg0, arg1, arg2, arg3, arg4);
                }
            }
        }
        public void ExecuteEvent<T, T1, T2, T3, T4, T5>(string eventName, T arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
        {
            List<Delegate> listeners;
            if (eventsDic.TryGetValue(eventName, out listeners))
            {
                foreach (var item in listeners)
                {
                    ((Action<T, T1, T2, T3, T4, T5>)item)(arg0, arg1, arg2, arg3, arg4, arg5);
                }
            }
        }

        #endregion
    }
}
